#include <WiFi.h>
#include <WiFiClient.h>

// —— 用户配置 ——
const char* ssid       = "BD3ND_J";       // Wi-Fi 名称
const char* password   = "12345678abc";   // Wi-Fi 密码
const char* callsign   = "BD3ND-10";       // 你的业余呼号（带 SSID）

const char* aprsServer = "rotate.aprs.net"; // APRS-IS 服务器
const uint16_t aprsPort = 14580;             // APRS-IS 端口

// ——— 固定坐标 (39°37.91'N, 118°8.21'E, 网格: OM99BP) ———
float latitude  = 39.63183;  // 北纬（正值）
float longitude = 118.13683; // 东经（正值）

// ——— APRS 图标配置 ———
// symTable: '/' 表示符号表 A；'\\' 表示符号表 B
// symChar: 参照 APRS 符号表选择字符
// 例如：
//   '>'  表示“车”
//   '+'  表示“红十字”
//   '*'  表示“雪花”
//   '?'  表示“问号”
const char symTable = '\\';   // 使用符号表 A
const char symChar  = '-';   // 使用 A 表中的“车”图标

// 若需使用 B 表符号，如问号：
// const char symTable = '\\';
// const char symChar  = '?';

const unsigned long sendInterval = 5UL * 60UL * 1000UL; // 5 分钟

WiFiClient client;
unsigned long lastSend = 0;
uint16_t passcodeNum = 0;

// —— APRS-IS Passcode 计算 ——
uint16_t calculatePasscode(const char* call) {
  String root = String(call);
  int dash = root.indexOf('-');
  if (dash > 0) root = root.substring(0, dash);
  root.toUpperCase();

  uint8_t hi = 0x73, lo = 0xE2;
  size_t len = root.length();
  for (size_t i = 0; i < len; i += 2) {
    uint8_t c1 = root.charAt(i);
    uint8_t c2 = (i + 1 < len) ? root.charAt(i + 1) : 0;
    hi ^= c1;
    lo ^= c2;
  }
  return (uint16_t)(((hi & 0x7F) << 8) | lo);
}

// —— APRS 坐标格式化函数 ——
String aprsLat(float lat) {
  char buf[16];
  char hemi = (lat >= 0) ? 'N' : 'S';
  lat = fabs(lat);
  int deg = int(lat);
  float min = (lat - deg) * 60.0;
  snprintf(buf, sizeof(buf), "%02d%05.2f%c", deg, min, hemi);
  return String(buf);
}
String aprsLon(float lon) {
  char buf[16];
  char hemi = (lon >= 0) ? 'E' : 'W';
  lon = fabs(lon);
  int deg = int(lon);
  float min = (lon - deg) * 60.0;
  snprintf(buf, sizeof(buf), "%03d%05.2f%c", deg, min, hemi);
  return String(buf);
}

// —— 发送 APRS-IS 报文 ——
void sendAprsPosition() {
  if (!client.connected()) {
    if (!client.connect(aprsServer, aprsPort)) {
      Serial.println("❌ 连接 APRS-IS 失败");
      return;
    }
    client.printf("user %s pass %u vers ESP32 0.1\r\n", callsign, passcodeNum);
    Serial.printf("✔ 登录 APRS-IS 成功 (passcode: %u)\r\n", passcodeNum);
  }

  // 构造带符号的报文：!lat[table]lon[symbol]comment
  String packet = String(callsign) + ">APRS,TCPIP*:="
    + aprsLat(latitude) + symTable + aprsLon(longitude) + symChar
    + " ESP32 OM99BP";

  client.println(packet);
  Serial.println("✉ 已发送: " + packet);
}

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("\n=== APRS-IS Position Reporter ===");

  passcodeNum = calculatePasscode(callsign);
  Serial.printf("🔑 Calculated passcode for %s: %u\r\n", callsign, passcodeNum);

  WiFi.begin(ssid, password);
  Serial.print("🔌 连接 Wi-Fi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print('.');
  }
  Serial.println("\n✔ Wi-Fi 已连接，IP: " + WiFi.localIP().toString());

  sendAprsPosition();
  lastSend = millis();
}

void loop() {
  if (millis() - lastSend >= sendInterval) {
    sendAprsPosition();
    lastSend = millis();
  }
}
